#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<unistd.h>
#include<arpa/inet.h>
#include<sys/socket.h>
#include<netinet/tcp.h>

void error_handing(char *message)
{
    fputs(message,stderr);
    fputc('\n',stderr);
    exit(1);
}
int main(int argc, char const *argv[])
{
    //步骤1：创建套接字
    int server_sock;
    server_sock = socket(PF_INET,SOCK_STREAM,IPPROTO_TCP);
    if (server_sock == -1)
    {
        error_handing("socket() error");
    }
    
    int option;
    socklen_t opt_len;
    opt_len = sizeof(option);

    //查询是否使用Nagle算法
    if(getsockopt(server_sock,SOL_SOCKET,SO_REUSEADDR,(void *)&option,&opt_len) == -1)
    {
        error_handing("getsockopt() error");
    }

    option = 1;
    //禁用Nagle算法 1：禁用，0（默认）：开启
    if(setsockopt(server_sock,IPPROTO_TCP,TCP_NODELAY,(void *)&option,opt_len) == -1)
    {
        error_handing("setsockopt() error");
    }

    option = -1;
    if(getsockopt(server_sock,SOL_SOCKET,SO_REUSEADDR,(void *)&option,&opt_len) == -1)
    {
        error_handing("getsockopt() error");
    }

    printf("查询当前是否禁用端口复用\n");
    switch (option)
    {
    case 0:
        printf("查询当前已经禁用端口复用\n");
        break;
    case 1:
        printf("查询当前已经开启端口复用\n");
        break;
    default:
        printf("错误\n");
        break;
    }
    //Time wait过程能够回复相应的应答，但是不能发送消息，需要进入Time wait过程就是为了防止直接断开，导致对方收不到应答，一直重传，最终也是异常终止
    
    /*
        Nagle算法是为了防止因数据包过多而发生过载
        Nagle算法要求必须收到上一次发送的ACK响应之后才会发送下一次数据，这样就容易将数据大部分放入输出缓冲区,收到ACK后一并发出

        如果不使用Nagle算法，发送流程就是：上一次发送完毕之后立即发送输出缓冲区内部的数据
        所以不使用Nagle算法，将对网络流量产生负面影响，因为即使只发送一个字节，其消息头也可能有几十个字节，
        缓冲区拥有一个字节就直接发送和缓存到两个字节后一并发送中间就多一个消息头的开销

        Nagle算法也不是什么时候都适用，根据传输数据的特性，网络流量未受太大影响时，不使用Nagle算法会更快，
        最典型的是“传输大文件数据”，将文件数据传入缓冲区不会花太多时间，因此，即使不使用Nagle算法，也会
        在装满输出缓冲时传输数据包，这样不仅不会增加数据包的数量，反而无需等待ACK,因此可以大大提高传输速度。

    */

    //禁用Nagle算法
    // int opt_val = 1;
    // if (setsockopt(server_sock,IPPROTO_TCP,TCP_NODELAY,(void *)&opt_val,sizeof(opt_val)))
    // {
    //     error_handing("setsockopt() error");
    // }
    

    // //步骤2：绑定监听端口
    // struct sockaddr_in server_addr;
    // memset(&server_addr,0,sizeof(server_addr));
    // server_addr.sin_family = AF_INET;
    // server_addr.sin_addr.s_addr = htonl(INADDR_ANY);
    // server_addr.sin_port = htons(atoi("3333"));
    // if (bind(server_sock,(struct sockaddr *)&server_addr,sizeof(server_addr)) == -1)
    // {
    //     error_handing("bind() error");
    // }

    // //步骤3：开启监听
    // if (listen(server_sock,5) == -1)
    // {
    //     error_handing("listen() error");
    // }
    
    // //步骤4：接受连接
    // int accept_sock;
    // struct sockaddr accept_addr;
    // socklen_t len = sizeof(accept_addr);
    // accept_sock = accept(server_sock,&accept_addr,&len);//第二个参数存储接入的客户端的地址信息
    // if (accept_sock == -1)
    // {
    //     error_handing("accept() error");
    // }
    
    // //步骤5：开始通讯
    // char message[10];
    // if (read(accept_sock,message,10) == -1)
    // {
    //     error_handing("read() error");
    // }
    
    // printf("Read message is %s\n",message);
    // if (write(accept_sock,message,10) == -1)
    // {
    //     error_handing("write() error");
    // }

    // //步骤6：关闭连接
    // close(accept_sock);
    close(server_sock);
    return 0;
}
